﻿using UnityEngine;
using Object = UnityEngine.Object;

namespace MyUtility.Extension
{
    public static class GameObject_Extension
    {
        public static void ResetParent(this GameObject child, GameObject parent, Vector3 pos)
        {
            child.transform.SetParent(parent.transform);
            child.ResetTransform();
            child.transform.position = pos;
        }

        public static void ResetParent(this GameObject child, GameObject parent, bool worldPositionStays = false)
        {
            child.transform.SetParent(parent.transform, worldPositionStays);
            child.ResetTransform(false, worldPositionStays);
        }

        public static void ResetParent(this GameObject child, Transform parent, bool worldPositionStays = false)
        {
            child.transform.SetParent(parent, worldPositionStays);
            child.ResetTransform(false, worldPositionStays);
        }


        public static void ResetParent(this Transform child, GameObject parent, bool worldPositionStays = false)
        {
            child.SetParent(parent.transform, worldPositionStays);
            child.ResetTransform(false, worldPositionStays);
        }


        public static void ResetParent(this Transform child, Transform parent, bool worldPositionStays = false)
        {
            child.SetParent(parent, worldPositionStays);
            child.ResetTransform(false, worldPositionStays);
        }


        public static void ResetTransform(this GameObject obj, bool isWorld = false, bool worldPositionStays = false)
        {
            ResetTransform(obj.transform, isWorld, worldPositionStays);
        }

        public static void ResetTransform(this Transform tran, bool isWorld = false, bool worldPositionStays = false)
        {
            if (worldPositionStays) return;

            if (!isWorld)
            {
                tran.localPosition = Vector3.zero;
                tran.localScale = Vector3.one;
                tran.localRotation = Quaternion.identity;
            }
            else
            {
                tran.position = Vector3.zero;
                tran.localScale = Vector3.one;
                tran.rotation = Quaternion.identity;
            }
        }

        public static float GetParticleDuration(this GameObject gameObject, bool includeChildren = true,
            bool includeInactive = false, bool allowLoop = false)
        {
            if (includeChildren)
            {
                var particles = gameObject.GetComponentsInChildren<ParticleSystem>(includeInactive);
                var duration = -1f;
                for (var i = 0; i < particles.Length; i++)
                {
                    var ps = particles[i];
                    var time = ps.GetDuration(allowLoop);
                    if (time > duration)
                    {
                        duration = time;
                    }
                }

                return duration;
            }
            else
            {
                var ps = gameObject.GetComponent<ParticleSystem>();
                if (ps != null)
                {
                    return ps.GetDuration(allowLoop);
                }
                else
                {
                    return -1f;
                }
            }

        }

        /// <summary>
        /// 实例化对象并设置父节点
        /// </summary>
        /// <param name="obj"> 待实例化的对象 </param>
        /// <param name="parent"> 父节点 </param>
        /// <returns> 实例化的对象 </returns>
        public static GameObject Instantiate(Object obj, GameObject parent = null)
        {
            if (obj == null)
            {
                Debug.LogError("Instantiate obj is nil");
                return null;
            }

            GameObject newObj = GameObject.Instantiate(obj) as GameObject;
            if (parent != null)
            {
                newObj.transform.SetParent(parent.transform);
            }

            newObj.transform.localPosition = Vector3.zero;
            newObj.transform.localScale = Vector3.one;
            newObj.transform.localRotation = Quaternion.identity;
            return newObj;
        }

        /// <summary>
        /// 获取或者创建MonoBehaviour脚本对象
        /// </summary>
        /// <typeparam name="T"> MonoBehaviour子类类型 </typeparam>
        /// <returns> T对象 </returns>
        public static T GetOrCreateMono<T>() where T : MonoBehaviour
        {
            var monoType = typeof(T);
            var monoName = monoType.Name;

            var obj = GameObject.Find(monoName);
            if (obj == null) obj = new GameObject(monoName);
            obj.ResetTransform();

            var mono = obj.GetComponent<T>();
            if (mono == null) mono = obj.AddComponent<T>();

            return mono;
        }

        public static void SetLayer(this GameObject obj, string layerName)
        {
            var layer = LayerMask.NameToLayer(layerName);
            if (obj.transform.childCount == 0)
            {
                obj.layer = layer;
                return;
            }

            obj.layer = layer;
            foreach (Transform child in obj.transform)
            {
                child.gameObject.layer = layer;
            }
        }
        
        public static void SetLayer(this GameObject obj, int layer)
        {
            if (obj.transform.childCount == 0)
            {
                obj.layer = layer;
                return;
            }

            obj.layer = layer;
            foreach (Transform child in obj.transform)
            {
                child.gameObject.layer = layer;
            }
        }

        public static GameObject FindOrCreateGobj(string name, GameObject parentGobj = null)
        {
            GameObject obj = null;
            if (parentGobj == null)
            {
                obj = GameObject.Find(name);
            }
            else
            {
                var tran = parentGobj.transform.Find(name);
                obj = tran == null ? null : tran.gameObject;
            }

            if (obj == null)
            {
                obj = new GameObject(name);
            }

            obj.ResetTransform();

            if (parentGobj != null)
            {
                obj.ResetParent(parentGobj);
            }

            return obj;
        }

        public static GameObject FindOrCreateGobj(string name, Transform parentTran = null)
        {
            GameObject parentObj = parentTran == null ? null : parentTran.gameObject;

            var obj = FindOrCreateGobj(name, parentObj);
            return obj;
        }

        public static Transform FindOrCreateTran(string name, GameObject parentGobj = null)
        {
            var obj = FindOrCreateGobj(name, parentGobj);

            var tran = obj.transform;
            return tran;
        }

        public static Transform FindOrCreateTran(string name, Transform parentTran = null)
        {
            var parentObj = parentTran == null ? null : parentTran.gameObject;

            var tran = FindOrCreateTran(name, parentObj);
            return tran;
        }

        public static T FindCom<T>(this GameObject obj, string path) where T : Component
        {
            if (obj == null) return default;
            var tran = obj.transform.Find(path);
            if (tran == null) return null;

            var com = tran.GetComponent<T>();
            return com;
        }

        public static GameObject Find(this GameObject obj, string namePath)
        {
            var tran = obj.transform.Find(namePath);
            if (tran == null) return null;

            var findObj = tran.gameObject;
            return findObj;
        }

    }
}
